package com.ruoyi.huanjing.service.impl;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import com.ruoyi.huanjing.mapper.FileInfoMapper;
import com.ruoyi.huanjing.domain.FileInfo;
import com.ruoyi.huanjing.service.IFileInfoService;

/**
 * 文件信息Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-07-12
 */
@Service
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements IFileInfoService
{
    @Autowired
    private FileInfoMapper fileInfoMapper;

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private RedisCache redisCache;

    /**
     * 查询文件信息
     * 
     * @param id 文件信息主键
     * @return 文件信息
     */
    @Override
    public FileInfo selectFileInfoById(Long id)
    {
        return fileInfoMapper.selectFileInfoById(id);
    }

    /**
     * 查询文件信息列表
     * 
     * @param fileInfo 文件信息
     * @return 文件信息
     */
    @Override
    public List<FileInfo> selectFileInfoList(FileInfo fileInfo)
    {
        return fileInfoMapper.selectFileInfoList(fileInfo);
    }

    /**
     * 新增文件信息
     * 
     * @param fileInfo 文件信息
     * @return 结果
     */
    @Override
    public int insertFileInfo(FileInfo fileInfo)
    {
        return fileInfoMapper.insertFileInfo(fileInfo);
    }

    /**
     * 修改文件信息
     * 
     * @param fileInfo 文件信息
     * @return 结果
     */
    @Override
    public int updateFileInfo(FileInfo fileInfo)
    {
        return fileInfoMapper.updateFileInfo(fileInfo);
    }

    /**
     * 批量删除文件信息
     * 
     * @param ids 需要删除的文件信息主键
     * @return 结果
     */
    @Override
    public int deleteFileInfoByIds(Long[] ids)
    {
        return fileInfoMapper.deleteFileInfoByIds(ids);
    }

    /**
     * 删除文件信息信息
     * 
     * @param id 文件信息主键
     * @return 结果
     */
    @Override
    public int deleteFileInfoById(Long id)
    {
        return fileInfoMapper.deleteFileInfoById(id);
    }

    @Override
    public void batchInsert(List<FileInfo> batchList) {
        fileInfoMapper.batchInsert(batchList);
    }

    @Override
    public List<FileInfo> listFilesByFolderPath(String folderPath) {
        return fileInfoMapper.selectFilesByFolderPath(folderPath);
    }

    private static List<String> yJList=new ArrayList<>(Arrays.asList("大气环境", "海面环境", "陆地环境", "水中环境"));

    private static List<String> tiffList=new ArrayList<>(Arrays.asList("中朝边境", "中印边境", "中缅边境","ESA_WorldCover_10m_2020_v100_Map"));

    private static final List<String> timeList = new ArrayList<>(Arrays.asList("大气辐射亮度"));


    @Override
    public AjaxResult bianli(String rootDir) {
        File rootDirectory = new File(rootDir);
        if (!rootDirectory.exists() || !rootDirectory.isDirectory()) {
            System.out.println(AjaxResult.error("根目录不存在或不是有效目录"));
        }

        try {
            // 先清空表
//            jdbcTemplate.execute("TRUNCATE TABLE file_info");
            //更新硬盘数据，先删除硬盘之前的数据，重新入库
            fileInfoMapper.delete(new QueryWrapper<FileInfo>().lambda().eq(FileInfo::getDiskIdentity,redisCache.getCacheObject("diskIdentity").toString()));

            // 用于批量收集文件信息（设置初始容量，减少扩容开销）
            List<FileInfo> batchList = new ArrayList<>(1000);
            // 扫描文件并收集到批量列表
            int totalCount = scanFiles(rootDirectory, batchList,rootDir,1);

            // 处理最后剩余的不足一批的数据
            if (!batchList.isEmpty()) {
                fileInfoMapper.batchInsert(batchList);
            }

            return AjaxResult.success("文件扫描完成，共处理 " + totalCount + " 个文件");
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("文件扫描失败：" + e.getMessage());
        }
    }

    /**
     * 存储盘符进缓存
     * @param disk
     * @return
     */
    @Override
    public boolean saveDisk(String disk) {
        //不传参的时候，说明是启动项目时调用，取扫描盘符，自动先赋值一个
        if (StringUtils.isEmpty(disk)) {
            List<String> diskScannerList = diskScanner();
            if (ObjectUtils.isNotEmpty(diskScannerList)) {
                redisCache.setCacheObject("disk", diskScannerList.get(diskScannerList.size()-1));
            }
        }
        //传参则更新redis
        else {
            redisCache.setCacheObject("disk", disk);
        }
        //扫描路径，看是否置灰树的
        isGray();
        String diskIdentity = readIdentifier(redisCache.getCacheObject("disk"));
        if (ObjectUtils.isNotEmpty(diskIdentity)) {
            redisCache.setCacheObject("diskIdentity",diskIdentity);
            System.out.println("diskIdentity："+diskIdentity);
        }
        return true;
    }

    // 标识文件的固定名称
    private static final String IDENTITY_FILE_NAME = "diskIdentity.txt";

    /**
     * 读取指定盘符下的硬盘标识
     * @param disk 盘符（如 "E:"、"G:" 或 "/Volumes/MyDisk"）
     * @return 标识文件中的内容，读取失败返回null
     */
    public String readIdentifier(String disk) {
        // 构建标识文件的完整路径
        String filePath = disk+"diskIdentity" + File.separator + IDENTITY_FILE_NAME;
        File identityFile = new File(filePath);

        // 检查文件是否存在
        if (!identityFile.exists() || !identityFile.isFile()) {
            System.out.println("标识文件不存在: " + filePath);
            return null;
        }

        // 读取文件内容
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                        new FileInputStream(identityFile),
                        StandardCharsets.UTF_8
                )
        )) {
            // 读取第一行非空内容作为标识
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (!line.isEmpty()) {
                    return line;
                }
            }
            System.out.println("标识文件内容为空: " + filePath);
            return null;
        } catch (FileNotFoundException e) {
            System.err.println("文件未找到: " + filePath);
        } catch (IOException e) {
            System.err.println("读取文件失败: " + e.getMessage());
        }
        return null;
    }

    /**
     * 扫描磁盘，获取盘符
     * @return
     */
    @Override
    public List<String> diskScanner() {
        try {
            // 获取所有磁盘根目录
            File[] roots = File.listRoots();

            if (roots == null || roots.length == 0) {
                return Collections.emptyList();
            }

            return Arrays.stream(roots)
                    .map(File::getAbsolutePath)
                    .collect(Collectors.toList());
        } catch (SecurityException e) {
            return Collections.emptyList();
        }
    }


    /**
     * 根据盘符扫描，看是否置灰全部目录
     * @return
     */
    @Override
    public boolean isGray(){
        String disk = redisCache.getCacheObject("disk").toString();

        // 1. 检查磁盘路径是否为空
        if (!StringUtils.hasText(disk)) {
            System.out.println("磁盘路径为空");
            return false;
        }

        // 2. 检查"环境数据"文件夹是否存在
        File envDataDir = new File(disk, "环境数据");
        if (!envDataDir.exists() || !envDataDir.isDirectory()) {
            redisCache.setCacheObject("isGray", true);//true代表没有路径，这是为了配合树里的是否禁用，没有路径时true代表禁用
            return false;
        }

        //todo  3. 检查四个环境文件夹是否都存在   这里先留存吧，因为硬盘的文件不一定有哪个环境的
        /*for (String dirName : yJList) {
            File envDir = new File(envDataDir, dirName);
            if (!envDir.exists() || !envDir.isDirectory()) {
                redisCache.setCacheObject("isGray", true);
                return false;
            }
        }*/
        redisCache.setCacheObject("isGray", false);
        return true;
    }

    /**
     * 获取tiff文件
     * @param map
     * @return
     */
    @Override
    public List<String> getTiffDisk(Map<String, String> map) {
        // 创建返回结果列表
        List<String> resultList = new ArrayList<>();

        // 从map中获取参数
        String fileName = map.get("fileName");
        String disk = redisCache.getCacheObject("disk");

        String baseUrl="";
        String filePath="";
        if ("ESA_WorldCover_10m_2020_v100_Map".equals(fileName)){
            baseUrl="/images/地物类型/ESA_WorldCover_10m_2020_v100_Map";
            filePath = disk + File.separator + "环境数据" + File.separator
                    + "陆地环境" + File.separator + "基本特性" + File.separator
                    + "地形地貌" + File.separator + "地物类型" + File.separator
                    + "ESA_WorldCover_10m_2020_v100_Map";
        }else {
            // 基础URL
            baseUrl = "/images/数字高程";
            // 要扫描的文件路径
            filePath = null;

            // 根据fileName设置不同的文件路径和URL
            if ("中朝边境".equals(fileName)) {
                // 构建文件路径，使用File.separator确保跨平台兼容性
                filePath = disk + File.separator + "环境数据" + File.separator
                        + "陆地环境" + File.separator + "基本特性" + File.separator
                        + "地形地貌" + File.separator + "数字高程" + File.separator
                        + "中朝边境";
                // 构建完整URL前缀
                baseUrl += "/中朝边境";
            }else if ("中缅边境".equals(fileName)) {
                filePath = disk + File.separator + "环境数据" + File.separator
                        + "陆地环境" + File.separator + "基本特性" + File.separator
                        + "地形地貌" + File.separator + "数字高程" + File.separator
                        + "中缅边境";
                // 构建完整URL前缀
                baseUrl += "/中缅边境";
            }else if ("中印边境".equals(fileName)) {
                filePath = disk + File.separator + "环境数据" + File.separator
                        + "陆地环境" + File.separator + "基本特性" + File.separator
                        + "地形地貌" + File.separator + "数字高程" + File.separator
                        + "中印边境";
                // 构建完整URL前缀
                baseUrl += "/中印边境";
            }
        }


        // 可以在这里添加其他fileName的判断条件

        // 如果文件路径为空，直接返回空列表
        if (filePath == null) {
            return resultList;
        }

        // 创建File对象
        File directory = new File(filePath);

        // 检查目录是否存在且是一个目录
        if (!directory.exists() || !directory.isDirectory()) {
            // 可以根据需要添加日志记录
            // log.warn("目录不存在或不是一个有效的目录: {}", filePath);
            return resultList;
        }

        // 获取目录下的所有文件
        File[] files = directory.listFiles();

        // 如果目录下没有文件，返回空列表
        if (files == null || files.length == 0) {
            return resultList;
        }

        // 遍历所有文件，拼接URL并添加到结果列表
        for (File file : files) {
            // 只处理文件，不处理子目录
            if (file.isFile()) {
                // 拼接URL（baseUrl + 文件名）
                String fileUrl = baseUrl + "/" + file.getName();
                resultList.add(fileUrl);
            }
        }
        // todo 暂存过滤num
//        List<String> collect = resultList.stream().filter(s -> s.contains("num")).collect(Collectors.toList());
        resultList.removeIf(s -> s.contains("num"));
        return  resultList;
    }

    private static List<String> tilsList=new ArrayList<>(Arrays.asList("台湾", "香港"));

    /**
     * 递归扫描目录，将文件信息收集到批量列表
     *
     * @param directory 目录
     * @param batchList 批量存储的列表
     * @param level
     * @return 总处理文件数
     */
    private int scanFiles(File directory, List<FileInfo> batchList, String currentTarget, int level) {
        int count = 0;
        File[] files = directory.listFiles();
        if (level==4){
            System.out.println(111);
        }

        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    if (tiffList.contains(file.getName())) {
                        FileInfo fileInfo = saveTiff(file);
                        batchList.add(fileInfo);
                        count++;
                        continue;
                    }
                    if (tilsList.contains(file.getName())) {
                        List<FileInfo> fileInfos = saveTils(file);
                        batchList.addAll(fileInfos);
                        count+=fileInfos.size();
                        continue;
                    }
                    // 递归扫描子目录，累加计数
                    count += scanFiles(file, batchList,file.getName(), level+1);
                    //特殊处理搞成

                } else {
                    if (!tiffList.contains(currentTarget)) {
                        // 处理文件并添加到批量列表
                        FileInfo fileInfo = processFile(file,currentTarget,level);
                        if (fileInfo != null) {
                            batchList.add(fileInfo);
                            count++;

                            // 当列表达到1000条时，批量插入并清空列表（批次大小可调整）
                            if (batchList.size() >= 1000) {
                                fileInfoMapper.batchInsert(batchList);
                                batchList.clear(); // 清空列表，继续收集
                            }
                        }
                    }

                }
            }
        }
        return count;
    }

    /**
     * 特殊处理高程入库
     * @param file
     * @return
     */
    private FileInfo saveTiff(File file) {
        String fileName = file.getName();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(fileName);
        fileInfo.setSize(formatFileSize(file.length()));
        // 获取完整路径（包含盘符），做路径处理
        String fullPath = file.getAbsolutePath(); // 例如：E:\环境数据\大气环境\...

        // 找到盘符后的起始位置（冒号+斜杠/反斜杠的下一个字符）
        int colonIndex = fullPath.indexOf(":");
        if (colonIndex != -1) {
            // 截取从盘符后的第一个字符开始的路径（跳过 "E:" 部分）
            String pathWithoutDrive = fullPath.substring(colonIndex + 1);

            fileInfo.setFilePath(pathWithoutDrive);
        } else {
            // 没有盘符的情况（如Linux/macOS），直接使用完整路径
            fileInfo.setFilePath(fullPath);
        }
        //存储硬盘标识

        fileInfo.setDiskIdentity(redisCache.getCacheObject("diskIdentity").toString());
        switch (fileName) {
            case "中印边境" -> fileInfo.setSize("5.70 GB");
            case "中朝边境" -> fileInfo.setSize("1.30 GB");
            case "中缅边境" -> fileInfo.setSize("1.82 GB");
            case "ESA_WorldCover_10m_2020_v100_Map" -> fileInfo.setSize("115 GB");
        }
        fileInfo.setFileType("tif");
        return  fileInfo;
    }

    /**
     * 特殊处理3Dtils入库
     * @param file
     * @return
     */
    private List<FileInfo> saveTils(File file) {
        String fullPath = file.getAbsolutePath();
        File tilsDirectory = new File(fullPath);
        File[] files = tilsDirectory.listFiles();
        List<FileInfo> fileInfoList = new ArrayList<>();
        // 基础URL
        String baseUrl = "/images"+"/"+"地面倾斜摄影";
        if (ObjectUtils.isNotEmpty(files)) {
            for (File file1 : files) {
                String fileName = file1.getName();
                if (fileName.contains(".zip")){
                    continue;
                }
                FileInfo fileInfo = new FileInfo();
                fileInfo.setFileName(fileName);
                fileInfo.setSize(formatFileSize(file1.length()));
                // 获取完整路径（包含盘符），做路径处理
                // 例如：E:\环境数据\大气环境\...

                //                String pathWithoutDrive = fullPath.substring(colonIndex + 1)+File.separator+file1.getName()+File.separator+"tileset.json";
                String pathWithoutDrive = baseUrl+"/"+file.getName()+"/"+file1.getName()+"/"+"tileset.json";
                //存储硬盘标识
                fileInfo.setFilePath(pathWithoutDrive);

                fileInfo.setDiskIdentity(redisCache.getCacheObject("diskIdentity").toString());
                fileInfo.setFileType("3Dtils");
                fileInfoList.add(fileInfo);
            }
        }

        return  fileInfoList;
    }

    // 计算文件夹大小的方法
    public long calculateFolderSize(String folderPath) throws IOException {
        Path path = Paths.get(folderPath);
        return Files.walk(path)
                .filter(Files::isRegularFile)
                .mapToLong(filePath -> {
                    try {
                        return Files.size(filePath);
                    } catch (IOException e) {
                        // 处理无法访问的文件
                        System.err.println("无法获取文件大小: " + filePath + "，原因: " + e.getMessage());
                        return 0;
                    }
                })
                .sum();
    }

    // 综合方法：获取文件夹大小并格式化
    public String getFormattedFolderSize(String folderPath) throws IOException {
        long sizeInBytes = calculateFolderSize(folderPath);
        return formatFileSize(sizeInBytes);
    }

    /**
     * 处理单个文件，返回FileInfo对象（不再直接插入数据库）
     */
    private FileInfo processFile(File file, String currentTarget, int level) {
        try {
            String fileName = file.getName();
            FileInfo fileInfo = new FileInfo();
            int dotIndex = fileName.lastIndexOf('.');
            if ("zip".equals(fileName.substring(dotIndex + 1))){
                fileInfo.setFileName(fileName.substring(0,dotIndex));
            }else {
                fileInfo.setFileName(fileName);
            }

            fileInfo.setSize(formatFileSize(file.length()));
//            fileInfo.setFilePath(file.getAbsolutePath());
            // 获取完整路径（包含盘符），做路径处理
            String fullPath = file.getAbsolutePath(); // 例如：E:\环境数据\大气环境\...

            // 找到盘符后的起始位置（冒号+斜杠/反斜杠的下一个字符）
            int colonIndex = fullPath.indexOf(":");
            if (colonIndex != -1) {
                // 截取从盘符后的第一个字符开始的路径（跳过 "E:" 部分）
                String pathWithoutDrive = fullPath.substring(colonIndex + 1);

                fileInfo.setFilePath(pathWithoutDrive);
            } else {
                // 没有盘符的情况（如Linux/macOS），直接使用完整路径
                fileInfo.setFilePath(fullPath);
            }
            //存储硬盘标识

            fileInfo.setDiskIdentity(redisCache.getCacheObject("diskIdentity").toString());

            // 设置文件类型（后缀）

            if (dotIndex > 0) {
                fileInfo.setFileType(fileName.substring(dotIndex + 1));
            }

            // 设置产品名称
            /*if (fileName.endsWith(".hdf")) {
                int firstDotIndex = fileName.indexOf('.');
                if (firstDotIndex > 0) {
                    fileInfo.setProductName(fileName.substring(0, firstDotIndex));
                }
            }
            else if (fileName.endsWith(".nc")) {
                int firstUnderscoreIndex = fileName.indexOf('_');
                if (firstUnderscoreIndex > 0) {
                    fileInfo.setProductName(fileName.substring(0, firstUnderscoreIndex));
                }
            }*/
            if (level == 6) {
                fileInfo.setProductName(currentTarget);
            }

            // 根据文件后缀调用不同的时间提取方法
            if (fileName.endsWith(".hdf")) {
                Date time = extractDateTime(fileName);
                if (time == null) {
                    System.out.println("跳过无法解析时间的文件：" + fileName);
                    return null;
                }
                fileInfo.setTime(time);
            }
            /*else if (fileName.endsWith(".nc")) {
                Date time = extractDateTimeFromNc(fileName);
                if (time == null) {
                    System.out.println("跳过无法解析时间的文件：" + fileName);
                    return null;
                }
                fileInfo.setTime(time);
            }
            else {
                System.out.println("跳过不支持的文件类型：" + fileName);
                return null;
            }*/

            return fileInfo; // 返回实体，由上层统一批量插入
        } catch (Exception e) {
            System.err.println("处理文件失败：" + file.getName() + " - " + e.getMessage());
            return null;
        }
    }

    /**
     * 从 .nc 文件名中提取时间信息，格式如 chinasea_202001_temp.nc
     */
    private Date extractDateTimeFromNc(String fileName) {
        try {
            // 匹配 .nc 文件名格式（如 chinasea_202001_temp.nc）
            // 提取 202001 部分，修正转义字符
            java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
                    "^.*_(\\d{4})(\\d{2})_.*\\.nc$");
            java.util.regex.Matcher matcher = pattern.matcher(fileName);

            if (matcher.find()) {
                String yearStr = matcher.group(1);  // 年
                String monthStr = matcher.group(2);  // 月

                // 构建完整的日期时间字符串（格式：yyyyMM）
                String dateTimeStr = yearStr + monthStr + "01";

                // 解析为 Date 对象
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                return sdf.parse(dateTimeStr);
            }
            return null;
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 从文件名中提取时间信息
     */
    /*private Date extractDateTime(String fileName) {
        try {
            // 匹配 MODIS 文件名格式（如 MOD021KM.A2023001.0035.061.2023001131703.hdf）
            // 提取 A 后面的 7 位数字（年+积日）和时间部分（0035）
            java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
                    "^.*\\.A(\\d{4})(\\d{3})\\.(\\d{4})\\..*\\.hdf$");
            java.util.regex.Matcher matcher = pattern.matcher(fileName);

            if (matcher.find()) {
                String yearStr = matcher.group(1);  // 年
                String dayOfYearStr = matcher.group(2);  // 积日
                String timeOfDayStr = matcher.group(3);  // 时分（如 0035）

                // 构建完整的日期时间字符串（格式：yyyyDDDHHmm）
                String dateTimeStr = yearStr + dayOfYearStr + timeOfDayStr;

                // 解析为 Date 对象
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyDDDHHmm");
                return sdf.parse(dateTimeStr);
            }
            return null;
        } catch (ParseException e) {
            return null;
        }
    }*/

    private Date extractDateTime(String fileName) {
        try {
            // 检查文件名是否以.hdf结尾
            if (fileName != null && fileName.endsWith(".hdf")) {
                // 将文件名按点分割
                String[] parts = fileName.split("\\.");

                // 确保文件名至少有两部分（xx.hdf）
                if (parts.length >= 2) {
                    // 获取最后两个点之间的数据
                    String timeData = parts[parts.length - 2];

                    // 检查时间数据格式是否为13位数字（如2023001131703或2021299153547）
                    if (timeData != null && timeData.length() == 13 && timeData.matches("\\d+")) {
                        // 解析为日期对象，格式为yyyyDDDHHmmss（年+积日+时+分+秒）
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyyDDDHHmmss");
                        return sdf.parse(timeData);
                    }
                }
            }
            return null;
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(long bytes) {
        if (bytes < 1024) return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        String pre = "KMGTPE".charAt(exp - 1) + "B";
        return String.format("%.2f %s", bytes / Math.pow(1024, exp), pre);
    }
}
